﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using Mvc4Demo.Core;
using Mvc4Demo.Models;
using MvcExtensions.Attributes;

namespace Mvc4Demo.Extensions
{
    public static class ControlExtensions
    {
        public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            object htmlAttributes = null)
        {
            var selectListItems = GetSelectListItems(htmlHelper, expression);

            return SelectExtensions.DropDownListFor(htmlHelper, expression, selectListItems, htmlAttributes);
        }

        public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper,
            Expression<Func<TModel, TProperty>> expression, string partialViewName)
        {
            var name = ExpressionHelper.GetExpressionText(expression);
            var model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
            var viewData = new ViewDataDictionary(helper.ViewData)
            {
                TemplateInfo = new TemplateInfo
                {
                    HtmlFieldPrefix = name
                }
            };

            return helper.Partial(partialViewName, model, viewData);
        }

        public static MvcHtmlString PartialFor<TModel>(this HtmlHelper<TModel> helper, string partialViewName, string htmlFieldPrefix)
        {
            var viewData = new ViewDataDictionary(helper.ViewData)
            {
                TemplateInfo = new TemplateInfo
                {
                    HtmlFieldPrefix = htmlFieldPrefix
                }
            };

            return helper.Partial(partialViewName, helper.ViewData.Model, viewData);
        }


        public static MvcHtmlString SodaCheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper,
                                                          Expression<Func<TModel, bool>> expression,
                                                          object checkboxAttributes = null,
                                                          object labelAttributes = null)
        {
            var attributeList = checkboxAttributes != null
                                    ? HtmlHelper.AnonymousObjectToHtmlAttributes(checkboxAttributes)
                                    : new RouteValueDictionary();

            var htmlString = htmlHelper.CheckBoxFor(expression, attributeList);

            var displayName = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).DisplayName;
            var lblAttributes = string.Empty;
            if (labelAttributes != null)
            {
                lblAttributes = KnockoutControlExtensions.ConvertDictionaryToAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(labelAttributes));
            }

            return MvcHtmlString.Create(string.Format("<{0} {3}>{1}{2}</{0}>", "label"
                                                      , htmlString, displayName,
                                                      lblAttributes));
        }

        public static MvcHtmlString RadioButtonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
                                                                       Expression<Func<TModel, TProperty>> expression,
                                                                       object htmlAttributes = null)
        {
            var selectListItems = GetSelectListItems(htmlHelper, expression);
            var mvcString = selectListItems.Aggregate("",
                                                      (c, item) =>
                                                      c +
                                                      string.Format("<div>{0}{1}</div>",
                                                                    InputExtensions.RadioButtonFor(htmlHelper,
                                                                                                   expression,
                                                                                                   item.Value,
                                                                                                   htmlAttributes),
                                                                    item.Text));
            return MvcHtmlString.Create(string.Format("<div>{0}</div>", mvcString));
        }

        #region static methods

        public static IEnumerable<SelectListItem> GetSelectListItems<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
        {
            var memberExpression = (MemberExpression)expression.Body;
            var propertyName = memberExpression.Member is PropertyInfo ? memberExpression.Member.Name : null;
            var containerType = memberExpression.Expression.Type;
            var propertyInfo = containerType.GetProperty(propertyName);

            var selectListItems = GetLookItems(propertyInfo);

            var propertyValue = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model;

            return selectListItems
                    .Select(x => new SelectListItem
                    {
                        Text = x.Description,
                        Value = x.Id, //x.Key,
                        Selected = propertyValue != null && x.Id == propertyValue.ToString(),
                    }); ;
        }

        internal static IEnumerable<Lookup> GetLookItems(PropertyInfo propertyInfo)
        {
            var attributes = propertyInfo.GetCustomAttributes(typeof(ServiceLookupAttribute)).ToList();

            var selectListItems = new List<Lookup>();

            if (attributes.Any())
            {
                var serviceLookup = (ServiceLookupAttribute)attributes.First();
                var serviceObj = DependencyResolver.Current.GetService(serviceLookup.LookupType);// Activator.CreateInstance(serviceLookup.LookupType);
                var methodInfo = serviceLookup.LookupType.GetMethod(serviceLookup.MethodName);
                var returnObj = methodInfo.Invoke(serviceObj, null) as IEnumerable<Lookup>;

                selectListItems = returnObj.ToList();
            }
            else if (propertyInfo.PropertyType.IsEnum)
            {
                selectListItems = LookupProviderbase.GetEnumLookup(propertyInfo.PropertyType).ToList();
            }
            return selectListItems;
        }

        public static string GetPropertyName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
        {
            var memberExpression = (MemberExpression)expression.Body;
            var propertyName = memberExpression.Member is PropertyInfo ? memberExpression.Member.Name : null;
            return propertyName;
        }

        public static string GetModelName<TModel>(this HtmlHelper<TModel> helper)
        {
            var modelName = helper.ViewData.Model.GetType().Name;
            var prefix = helper.ViewData.TemplateInfo.HtmlFieldPrefix;
            return string.IsNullOrEmpty(prefix) ? modelName : string.Format("{0}.{1}", modelName, prefix);
        }

        #endregion

    }
}